import jsonpath
from django.db import models

from super.dynamic.core.props import NULL, BLANK, DEFAULT, MAX_LENGTH
from super.dynamic.exceptions import FieldNotFoundError


class Field:
    default_field = ''
    field_transform = {}
    field_props_mapping = {}
    field_default_props = {}
    transform_fields = ()

    def __init__(self, field_props, *args, **kwargs):
        self.field_props = field_props
        self.field_type = kwargs.get('field_type')

    def get_child_field(self):
        return self.field_props.get('type') or self.field_props.get('widget') or self.get_default_field()

    def parse_props(self):
        """
        解析表单字段属性到模型字段属性
        """
        kwargs = {}
        field_props = self.field_props_mapping
        default_fields = self.field_default_props
        if self.default_field:
            child_value = self.get_child_field()
            field_props = self.field_props_mapping.get(child_value, {})
            default_fields = self.field_default_props.get(child_value, {})
        for p, f in field_props.items():
            kwargs[f] = self.field_props.get(p)
        # 合并公共字段属性
        kwargs.update(self.get_field_props())
        return dict(default_fields, **kwargs)

    def get_field(self):
        return self.field_transform.get(self.get_child_field())

    def to_python(self):
        field = self.get_field()
        if not field:
            raise FieldNotFoundError(
                f'field not found. type: {self.field_props.get("type")}, '
                f'child_field: {self.get_child_field()}, class: {self.__class__}'
            )
        f = field(**self.parse_props())
        setattr(f, 'form_type', self.field_type)
        return f

    def get_default_field(self):
        return self.default_field

    def get_field_props(self):
        if not self.transform_fields:
            return {}
        field_props = {}
        for field in self.transform_fields:
            for field_name, field_prop in field.items():
                value = jsonpath.jsonpath(self.field_props, field_prop.get('selector'))
                if not value:
                    continue
                value = value[0]
                if value is not None:
                    if field_prop.get('include_types'):
                        if self.field_props.get('type') in field_prop.get('include_types'):
                            field_props[field_name] = value
                    elif field_prop.get('logic'):
                        field_props[field_name] = not value
                    else:
                        field_props[field_name] = value
        return field_props


class StrField(Field):
    default_field = 'text'
    field_transform = {
        'textarea': models.TextField,
        # 'image': models.ImageField,
        'text': models.CharField,
    }
    field_default_props = {
        'text': {'max_length': 256, 'default': '', 'blank': True},
        'select': {'max_length': 256, 'default': '', 'blank': True},
        'radio': {'max_length': 128},
        'textarea': {'default': '', 'blank': True}
    }
    transform_fields = [NULL, BLANK, DEFAULT, MAX_LENGTH]


class ArrayField(Field):
    field_default_props = {'default': list}

    def get_field(self):
        return models.JSONField


class ObjectField(Field):
    field_default_props = {'default': dict}

    def get_field(self):
        return models.JSONField


class DateField(Field):
    default_field = 'date'
    field_transform = {
        'datetime': models.DateTimeField,
        'date': models.DateField,
        # 'image': models.ImageField,
        'dates': models.JSONField,
        'year': models.CharField,
        'month': models.CharField,
        'week': models.CharField
    }
    transform_fields = [NULL, BLANK]

    field_default_props = {
        'dates': {'default': list},
        'year': {'max_length': 128, 'default': '', 'blank': True},
        'month': {'max_length': 128},
        'week': {'max_length': 128}
    }

    # def get_field(self):
    #     return models.DateField


class TimeField(Field):

    def get_field(self):
        return models.TimeField


class NumberField(Field):
    field_default_props = {'default': 0}
    transform_fields = [NULL, BLANK]

    def get_field(self):
        return models.IntegerField


class BooleanField(Field):
    field_default_props = {'default': False}
    transform_fields = [DEFAULT]

    def get_field(self):
        return models.BooleanField


class RangeField(Field):
    def get_field(self):
        return models.JSONField


class FloatField(Field):
    field_default_props = {'default': 0}
    transform_fields = [NULL, BLANK]

    def get_field(self):
        return models.FloatField


FIELD_MAPPING = {
    "input": StrField,
    'textarea': StrField,
    "date": DateField,
    "time": TimeField,
    "radio": StrField,
    'date-range': ArrayField,
    'time-range': ArrayField,
    "checkbox": ArrayField,
    "select": ArrayField,
    "number": NumberField,
    "switch": BooleanField,
    "rate": FloatField,
    "color": StrField,
    "slider": FloatField,
    "range": RangeField,
}
